package wangjg.dbfx.mapping;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Map.Entry;
import java.util.Set;


/**
 * 映射SQL
 * @author wangjg
 *
 */
public class SqlMapping{
	public static final int REFER_COLUMN_NAME = 1;
	public static final int REFER_FIELD_NAME = 2;
	public static final int REFER_ALL = 3;

	private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
	
	private EntityInfoManager ef ;
	
	public SqlMapping(EntityInfoManager ef) {
		this.ef = ef;
	}
	
	public EntityInfo getEntityInfo(Class<?> c){
		return ef.getEntityInfo(c);
	}
	
	public PreparedStatement getInsertStatement(Connection conn, Object entity) throws SQLException{
		Class<?> c = entity.getClass();
		EntityInfo ei=this.getEntityInfo(c);
		StringBuilder sb=new StringBuilder();
		sb.append("insert into ");
		sb.append(ei.getTable());
		sb.append(" (");
		Set<Entry<String,FieldInfo>> entrySet = ei.getColumnMap().entrySet();
		int cc = 0;
		for (Entry<String, FieldInfo> entry : entrySet) { 
			String name=entry.getKey();
			FieldInfo fi = entry.getValue();
			if(ei.getId().isAuto() && fi.equals(ei.getId())){
				continue;
			}
			sb.append(name);
			sb.append(',');
			cc++;
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append(") values (");
		for(int i=0;i<cc;i++){
			sb.append("?,");
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append(")");
		String sql = sb.toString();
		
		//jdbc
        PreparedStatement stmt = conn.prepareStatement(sql);
		entrySet = ei.getColumnMap().entrySet();
		int i=1;
		for (Entry<String, FieldInfo> entry : entrySet) {
			FieldInfo fi = entry.getValue();
			if(ei.getId().isAuto() && fi.equals(ei.getId())){
				continue;
			}
			try {
				Object v = fi.getReadMethod().invoke(entity, EMPTY_OBJECT_ARRAY);
				stmt.setObject(i++, v);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return stmt;
	}

	public PreparedStatement getUpdateStatement(Connection conn, Object entity) throws SQLException{
		Class<?> c = entity.getClass();
		EntityInfo ei=this.getEntityInfo(c);
        String sql = null;
		StringBuilder sb=new StringBuilder();
		sb.append("update ");
		sb.append(ei.getTable());
		sb.append(" set ");
		Set<Entry<String,FieldInfo>> entrySet = ei.getColumnMap().entrySet();
		for (Entry<String, FieldInfo> entry : entrySet) {
			String name=entry.getKey();
			FieldInfo fi = entry.getValue();
			if(fi.equals(ei.getId())){
				continue;
			}
			sb.append(name);
			sb.append("=?,");
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append(" where ");
		sb.append(ei.getId().getColumnName());
		sb.append("=?");
		sql = sb.toString();
		
		//jdbc
        PreparedStatement stmt = conn.prepareStatement(sql);
		entrySet = ei.getColumnMap().entrySet();
		int i=1;
		for (Entry<String, FieldInfo> entry : entrySet) {
			FieldInfo fi = entry.getValue();
			if(ei.getId().isAuto() && fi.equals(ei.getId())){
				continue;
			}
			try {
				Object v = fi.getReadMethod().invoke(entity, EMPTY_OBJECT_ARRAY);
				stmt.setObject(i++,v);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		try {
			stmt.setObject(i, ei.getId().getReadMethod().invoke(entity, EMPTY_OBJECT_ARRAY));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return stmt;
	}
	
	public PreparedStatement getDeleteStatement(Connection conn, Object entity) throws SQLException{
		Class<?> clazz = entity.getClass();
		Object idVal = this.getIdValue(entity);
		return this.getDeleteStatement(conn, clazz, idVal);
	}
	
	public PreparedStatement getDeleteStatement(Connection conn, Class<?> clazz, Object id) throws SQLException{
		EntityInfo ei = getEntityInfo(clazz);
		String sql="delete from "+ei.getTable()+" where "+ei.getId().getFieldName()+"=?";
		PreparedStatement stmt = conn.prepareStatement(sql);
		stmt.setObject(1, id);
		return stmt;
	}

	private Object getIdValue(Object entity){
		EntityInfo ei = this.getEntityInfo(entity.getClass());
		Object id;
		try {
			id = ei.getId().getReadMethod().invoke(entity, EMPTY_OBJECT_ARRAY);
			return id;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
